package com.etcsoft.examples.binding;

import org.eclipse.core.databinding.AggregateValidationStatus;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.databinding.validation.IValidator;
import org.eclipse.core.databinding.validation.ValidationStatus;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

import com.etcsoft.examples.binding.model.Address;
import com.etcsoft.examples.binding.model.Person;

public class View extends ViewPart {
    public static final String ID = "com.etcsoft.examples.binding.view";

    private Person person;

    private Text txtFirstName;
    private Text txtAge;
    private Button btnMarried;
    private Combo comboGender;
    private Text txtCountry;
    private Label errorLabel;

    @Override
    public void createPartControl(Composite parent) {
        person = createPerson();
        GridLayout layout = new GridLayout(2, false);
        layout.marginRight = 5;
        parent.setLayout(layout);

        Label firstLabel = new Label(parent, SWT.NONE);
        firstLabel.setText("Firstname: ");
        txtFirstName = new Text(parent, SWT.BORDER);

        GridData gridData = new GridData();
        gridData.horizontalAlignment = SWT.FILL;
        gridData.grabExcessHorizontalSpace = true;
        txtFirstName.setLayoutData(gridData);

        Label ageLabel = new Label(parent, SWT.NONE);
        ageLabel.setText("Age: ");
        txtAge = new Text(parent, SWT.BORDER);

        gridData = new GridData();
        gridData.horizontalAlignment = SWT.FILL;
        gridData.grabExcessHorizontalSpace = true;
        txtAge.setLayoutData(gridData);

        Label marriedLabel = new Label(parent, SWT.NONE);
        marriedLabel.setText("Married: ");
        btnMarried = new Button(parent, SWT.CHECK);

        Label genderLabel = new Label(parent, SWT.NONE);
        genderLabel.setText("Gender: ");
        comboGender = new Combo(parent, SWT.NONE);
        comboGender.add("Male");
        comboGender.add("Female");

        Label countryLabel = new Label(parent, SWT.NONE);
        countryLabel.setText("Country");
        txtCountry = new Text(parent, SWT.BORDER);

        Button button1 = new Button(parent, SWT.PUSH);
        button1.setText("Write model");
        button1.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                System.out.println("Firstname: " + person.getFirstName());
                System.out.println("Age " + person.getAge());
                System.out.println("Married: " + person.isMarried());
                System.out.println("Gender: " + person.getGender());
                System.out.println("Country: " + person.getAddress().getCountry());
            }
        });

        Button button2 = new Button(parent, SWT.PUSH);
        button2.setText("Change model");
        button2.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                person.setFirstName("Lars");
                person.setAge(person.getAge() + 1);
                person.setMarried(!person.isMarried());
                if (person.getGender().equals("Male")) {

                } else {
                    person.setGender("Male");
                }
                if (person.getAddress().getCountry().equals("Deutschland")) {
                    person.getAddress().setCountry("USA");
                } else {
                    person.getAddress().setCountry("Deutschland");
                }
            }
        });

        // this label displays all errors of all bindings
        Label descAllLabel = new Label(parent, SWT.NONE);
        descAllLabel.setText("All Validation Problems:");
        errorLabel = new Label(parent, SWT.NONE);
        gridData = new GridData();
        gridData.horizontalAlignment = SWT.FILL;
        gridData.grabExcessHorizontalSpace = true;
        gridData.horizontalAlignment = GridData.FILL;
        gridData.horizontalSpan = 1;
        errorLabel.setLayoutData(gridData);

        // perform the binding
        bindValues();
    }

    private void bindValues() {
        // The DataBindingContext object will manage the databindings
        // Lets bind it
        DataBindingContext ctx = new DataBindingContext();

        // firstname binding
        IObservableValue widgetValue = WidgetProperties.text(SWT.Modify).observe(txtFirstName);
        IObservableValue modelValue = BeanProperties.value(Person.class, "firstName").observe(
                person);
        UpdateValueStrategy update = new UpdateValueStrategy();
        update.setAfterConvertValidator(new StringLongerThenTwo());
        ctx.bindValue(widgetValue, modelValue, update, null);

        // Bind the age including a validator
        widgetValue = WidgetProperties.text(SWT.Modify).observe(txtAge);
        modelValue = BeanProperties.value(Person.class, "age").observe(person);
        // add an validator so that age can only be a number
        IValidator validator = new IValidator() {
            @Override
            public IStatus validate(Object value) {
                if (value instanceof Integer) {
                    String s = String.valueOf(value);
                    if (s.matches("\\d*")) {
                        return ValidationStatus.ok();
                    }
                }
                return ValidationStatus.error("Not a number");
            }
        };

        UpdateValueStrategy strategy = new UpdateValueStrategy();
        strategy.setBeforeSetValidator(validator);

        Binding bindValue = ctx.bindValue(widgetValue, modelValue, strategy, null);
        // add some decorations
        // 에러 메시지는 어디에 존재? 물론 사용자 정의 할 수 있지만, 기본 메시지는 어디에?
        ControlDecorationSupport.create(bindValue, SWT.TOP | SWT.LEFT);

        // married binding
        widgetValue = WidgetProperties.selection().observe(btnMarried);
        modelValue = BeanProperties.value(Person.class, "married").observe(person);
        ctx.bindValue(widgetValue, modelValue);

        // gender binding
        widgetValue = WidgetProperties.selection().observe(comboGender);
        modelValue = BeanProperties.value("gender").observe(person);
        ctx.bindValue(widgetValue, modelValue);

        // address field is bound to the Ui
        widgetValue = WidgetProperties.text(SWT.Modify).observe(txtCountry);
        modelValue = BeanProperties.value(Person.class, "address.country").observe(person);
        ctx.bindValue(widgetValue, modelValue);

        // listen to all errors via this binding
        // we do not need to listen to any SWT event on this label as it never
        // changes independently
        final IObservableValue errorObservable = WidgetProperties.text().observe(errorLabel);
        // this one listenes to all changes
        ctx.bindValue(errorObservable, new AggregateValidationStatus(ctx.getBindings(),
                AggregateValidationStatus.MAX_SEVERITY), null, null);
    }

    private Person createPerson() {
        Person person = new Person();
        Address address = new Address();
        address.setCountry("Deutschland");
        person.setAddress(address);
        person.setFirstName("John");
        person.setLastName("Doo");
        person.setGender("Male");
        person.setAge(12);
        person.setMarried(true);
        return person;
    }

    @Override
    public void setFocus() {
        // TODO Auto-generated method stub

    }

}